package org.esgi.ppascript.controllers;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.esgi.dao.FormDao;
import org.esgi.dao.UserDao;
import org.esgi.model.impl.Answer;
import org.esgi.model.impl.Form;
import org.esgi.model.impl.Question;
import org.esgi.model.impl.User;
import org.esgi.model.interfaces.IAnswer;
import org.esgi.model.interfaces.IForm;
import org.esgi.model.interfaces.IQuestion;
import org.esgi.model.interfaces.IUser;


/**
 * Servlet for admin management each call to the servlet is redirected to the function corresponding to the given action
 * exemple : /admin/add_form call the method add_form(HttpServletRequest request, HttpServletResponse response)
 * action methods(with no views, ex:login call) are usually name with underscores (user_login) where views methods are called on camelCase(pageNotFound)
 * @author Julien Baczynsky
 */
public class AdminServlet extends HttpServlet 
{
	/**
	 * auto generated for serialization purposes
	 */
	private static final long serialVersionUID = 1L;
	private Pattern _actionPattern;
	private String servletDir = "/admin";

	/**
	 * initialize the servlet
	 * loads the users
	 * loads the forms
	 */
	@Override
	public void init(ServletConfig config) throws ServletException 
	{
		super.init(config);
		_actionPattern = Pattern.compile(".+/([^/]+)$");
		File file = new File(this.getServletContext().getRealPath("/WEB-INF/users/users.xml"));
		UserDao.getSharedUserDao().setFile(file);
		IUser user = new User();
		user.setLogin("admin");
		user.setPassword("admin");
		user.setIsSuper(true);
		user.setCanCreate(true);
		user.setCanModify(true);
		user.setCanRead(true);
		UserDao.getSharedUserDao().addUser(user);
		file = new File(this.getServletContext().getRealPath("/WEB-INF/forms/"));
		FormDao.getSharedFormDao().setDirectory(file);
	}
	/**
	 * method called by each url redirected to the admin servlet
	 * automatically inflate view file for pages or return file content for resources(css, js, images)
	 * redirect to page not found if introspection on action throws an exception
	 */
	@Override
	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		Matcher m = _actionPattern.matcher(request.getRequestURI());
		String action = m.find()?m.group(1):null;
		//request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response)	
		try
		{
			//System.out.println("action : |"+action+"|");

			if(null==action || action.contains("*"))
				response.sendRedirect(request.getContextPath()+servletDir+"/index");
			else{
				if(action.contains("WebService")){
					this.getClass().getMethod(action, HttpServletRequest.class, HttpServletResponse.class).invoke(this, request, response);
					//System.out.println("WebService");
				}else{
					if(action.contains(".css") || action.contains(".js") || action.contains(".png") || action.contains(".jpg") || action.contains(".xml") ){
						inflateFile(request,response);
					}else{
						this.getClass().getMethod(action, HttpServletRequest.class, HttpServletResponse.class).invoke(this, request, response);
						setBaseAttributes(request,response);
						inflateView(request, response);
					}
				}
			}
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
			response.sendRedirect(request.getContextPath()+servletDir+"/pageNotFound");
		}

	}
	/*
	public void add_form(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{	
		IForm form = new Form();
		form.setName("test");
		List<IQuestion> questions = new ArrayList<IQuestion>();
		List<IAnswer> answers = new ArrayList<IAnswer>();
		Question q = new Question();
		q.setId("id1");
		q.setText("Le texte 1");
		IAnswer a = new Answer();
		a.setText("reponse 1");
		a.setNextQuestionId("id2");
		answers.add(a);
		a = new Answer();
		a.setText("reponse 2");
		a.setNextQuestionId("id3");
		answers.add(a);
		q.setAnswers(answers);
		questions.add(q);
		form.setQuestions(questions);
		//File file = new File(this.getServletContext().getRealPath("/WEB-INF/users/form_test.xml"));
		System.out.println("form create : "+FormDao.getSharedFormDao().saveForm(form));
		System.out.println(FormDao.getSharedFormDao().getAllForms().size());
		System.out.println(FormDao.getSharedFormDao().loadFormWithId("13560389295895461"));
		/*
		IForm loadedForm = FormDao.getSharedFormDao().loadFormWithId("1");

		questions = loadedForm.getQuestions();
		if(questions != null)
		{
			for(int i=0; i<questions.size(); i++)
			{
				IQuestion question = questions.get(i);
				System.out.println("q"+i+" (id="+question.getId()+") : "+question.getText());
				answers = question.getAnswers();
				if(answers != null)
				{
					for(int j=0; j<answers.size(); j++)
					{
						IAnswer answer = answers.get(j);
						System.out.println("	a"+j+" (next="+answer.getNextQuestionId()+") : "+answer.getText());
					}
				}        		
			}
		}

		System.out.println(loadedForm.getQuestions());
	 */
	/*}
	 */
	/**
	 * Nothing to do here, method exists to avoid a NoSuchMethodException loop
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void pageNotFound(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
	}
	/**
	 * Index page
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void index(HttpServletRequest request, HttpServletResponse response) throws IOException{
		HttpSession session = request.getSession(true);
		if((Boolean)session.getAttribute("logged") ==null || !(Boolean)session.getAttribute("logged"))
			response.sendRedirect(request.getContextPath()+servletDir+"/login");
		
		//System.out.println("contextPath :"+ request.getRequestURL());
		//System.out.println(request.getMethod());

		//inflateView(request,response);
	}

	/**
	 * login page
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		//System.out.println("error :"+request.getAttribute("error"));
	}
	/**
	 * logout action
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException{
		request.getSession().setAttribute("logged", false);
		response.sendRedirect(request.getContextPath()+servletDir+"/index");
	}
	/**
	 * login action, check if the user login and password are correct and create a session for the user
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void user_login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		HttpSession session = request.getSession(true);

		String login = (String) request.getParameter("login");
		String password = (String) request.getParameter("password") ;
		//System.out.println("login : "+login);
		IUser user = UserDao.getSharedUserDao().getUser(login, password);
		if(null==user){//login error, redirecting user to login page
			session.setAttribute("error", "true");
			session.setAttribute("login", login);
			response.sendRedirect(request.getContextPath()+servletDir+"/login");
		}else{
			session.setAttribute("logged", true);
			session.setAttribute("login", user.getLogin());
			session.setAttribute("password", user.getPassword());
			session.removeAttribute("error");
			response.sendRedirect(request.getContextPath()+servletDir+"/index");
		}
	}
	/**
	 * method called to add default attributes to jsp
	 * servletUrl and baseUrl
	 * @param request
	 * @param response
	 */
	private void setBaseAttributes(HttpServletRequest request,
			HttpServletResponse response) {
		String servletUrl = request.getRequestURL().toString();
		servletUrl= servletUrl.substring(0, servletUrl.lastIndexOf("/"));
		request.setAttribute("servletUrl",servletUrl);
		URI baseUrl;
		try {
			baseUrl = new URI(request.getRequestURI());
			request.setAttribute("baseUrl",baseUrl.getHost());
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}	
	}

	/**
	 * method called to inflate views for each action in forwarded response
	 * load the "action".jsp file
	 * @param request
	 * @param response
	 */
	private void inflateView(HttpServletRequest request,
			HttpServletResponse response) {
		String action=request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/")+1);
		//System.out.println("action: "+action);
		try {
			request.getRequestDispatcher("/WEB-INF"+servletDir+"/"+action+".jsp").forward(request, response);
		} catch (ServletException e) {
			e.printStackTrace();
		} catch (IOException e) {
			//System.out.println("There is no view for this action : "+action);
		} catch (IllegalStateException e){
			//e.printStackTrace();
		}
	}
	/**
	 * method called for resource file, just push file content into forwarded response
	 * @param request
	 * @param response
	 */
	private void inflateFile(HttpServletRequest request,
			HttpServletResponse response) {
		String action=request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/")+1);
		String dirs=request.getRequestURI().substring(request.getRequestURI().lastIndexOf("admin/")+6, request.getRequestURI().lastIndexOf("/")+1);
		//System.out.println("ressource: "+action);
		//System.out.println("dirs: "+dirs);
		try {
			request.getRequestDispatcher("/WEB-INF"+servletDir+"/"+dirs+action).forward(request, response);
		} catch (ServletException e) {
			e.printStackTrace();
		} catch (IOException e) {
			//System.out.println("There is no view for this action : "+action);
		} catch (IllegalStateException e){
			//e.printStackTrace();
		}
	}
	/**
	 * headers action
	 * @param request
	 * @param response
	 */
	public void headers(HttpServletRequest request, HttpServletResponse response){
		//System.out.println("headers");
	}
	/*
	public void testForm(HttpServletRequest request, HttpServletResponse response){
		System.out.println("Select"+request.getAttribute("select"));
	}*/
	/**
	 * View to create a user
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void userCreate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!isUserLoggedSuper(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/index?credentialError=true");
		}
	}
	/**
	 * returns the logged user or null
	 * @param request
	 * @return
	 */
	private IUser getUserLogged(HttpServletRequest request){
		HttpSession session = request.getSession(true);
		String login = (String) session.getAttribute("login");
		String password = (String)session.getAttribute("password");
		return UserDao.getSharedUserDao().getUser(login, password, true);
	}
	/**
	 * check if logged user is super user
	 * @param request
	 * @return
	 */
	private boolean isUserLoggedSuper(HttpServletRequest request){
		IUser user = getUserLogged(request);
		return (null != user && user.isSuper());
	}
	/**
	 * check if logged user has read rights
	 * @param request
	 * @return
	 */
	@SuppressWarnings("unused")
	private boolean UserLoggedCanRead(HttpServletRequest request){
		IUser user = getUserLogged(request);
		return (null != user && (user.isSuper() || user.canRead()));
	}
	/**
	 * check if logged user has create rights
	 * @param request
	 * @return
	 */
	@SuppressWarnings("unused")
	private boolean UserLoggedCanCreate(HttpServletRequest request){
		IUser user = getUserLogged(request);
		return (null != user && (user.isSuper() || user.canCreate()));
	}
	/**
	 * check if logged user has modify rights
	 * @param request
	 * @return
	 */
	private boolean UserLoggedCanModify(HttpServletRequest request){
		IUser user = getUserLogged(request);
		return (null != user && (user.isSuper() || user.canModify()));
	}
	/**
	 * action to create a user in file
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void user_create(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!isUserLoggedSuper(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/index?credentialError=true");
		}
		String login = (String) request.getParameter("login");
		String password = (String) request.getParameter("password") ;
		boolean canCreate= request.getParameter("canCreate") != null?true:false;
		boolean canModify= request.getParameter("canModify") != null?true:false;
		boolean canRead= request.getParameter("canRead") != null?true:false;
		//System.out.println("login :"+login+"| pwd :"+password+"| canCreate :"+canCreate+"| canModify :"+canModify+"| canRead :"+canRead);
		IUser user = new User();
		user.setLogin(login);
		user.setPassword(password);
		user.setCanModify(canModify);
		user.setCanCreate(canCreate);
		user.setCanRead(canRead);
		user.setIsSuper(false);
		UserDao.getSharedUserDao().addUser(user);
		//System.out.println(UserDao.getSharedUserDao());
		response.sendRedirect(request.getContextPath()+servletDir+"/userList");
		//Writer writer = response.getWriter();
		//writer.write("<html><head><title>User Create</title></head><body>"+user.canCreate()+"</body></html>");
	}
	/**
	 * action to delete the a user
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void user_delete(HttpServletRequest request, HttpServletResponse response) throws IOException{
		if(!isUserLoggedSuper(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/index?credentialError=true");
		}
		String user_id=(String)request.getParameter("user_id");
		//System.out.println("Delete user: "+user_id);
		IUser user = new User();
		user.setLogin(user_id);
		UserDao.getSharedUserDao().deleteUser(user);
		response.sendRedirect(request.getContextPath()+servletDir+"/userList");
	}
	/**
	 * View to display the user list
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void userList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!isUserLoggedSuper(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/index?credentialError=true");
		}
		ArrayList<IUser> userList = (ArrayList<IUser>) UserDao.getSharedUserDao().getAllUsers();
		System.out.println(userList);
		IUser admin = new User();
		admin.setLogin("admin");
		userList.remove(admin);
		request.setAttribute("userList",userList);
	}

	/**
	 * View to create a form
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void formCreate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!UserLoggedCanCreate(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/formList?credentialError=true");
		}
	}
	/**
	 * action to create a form in files
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void form_create(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!UserLoggedCanCreate(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/formList?credentialError=true");
		}
		String formName = request.getParameter("formName");
		if(null != formName){
			IForm form = new Form();
			form.setId(UUID.randomUUID().toString());
			form.setName(formName);

			List<IQuestion> questions = new ArrayList<IQuestion>();
			int q = 0;
			while (null != request.getParameter("question"+q)){
				String questionText = request.getParameter("question"+q);
				IQuestion question = new Question();
				question.setId(""+q);
				question.setText(questionText);

				int a = 0;
				List<IAnswer> answers = new ArrayList<IAnswer>();
				while (null != request.getParameter("answer_"+q+"_"+a)){
					IAnswer answer = new Answer();
					String answerText = request.getParameter("answer_"+q+"_"+a);
					String answerNext = request.getParameter("answerNQ_"+q+"_"+a);
					answer.setText(answerText);
					if(answerNext != null){
						try {
							answer.setNextQuestionId("" + (Integer.parseInt(answerNext)-1));	
						} catch (Exception e) {
							// TODO: handle exception
						}

					}

					answers.add(answer);
					a++;
				}
				question.setAnswers(answers);
				questions.add(question);
				q++;
			}
			form.setQuestions(questions);
			FormDao.getSharedFormDao().saveForm(form);
			//File file = new File(this.getServletContext().getRealPath("/WEB-INF/forms/"+ formName + ".xml"));
			//System.out.println("form create : "+FormDao.getSharedFormDao().saveFormToFile(form, file));
		}

		response.sendRedirect(request.getContextPath()+servletDir+"/formList");
		//Writer writer = response.getWriter();
		//writer.write("<html><head><title>User Create</title></head><body>"+user.canCreate()+"</body></html>");
	}
	/**
	 * action to delete a form
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void form_delete(HttpServletRequest request, HttpServletResponse response) throws IOException{
		if(!UserLoggedCanModify(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/formList?credentialError=true");
		}
		String form_id=(String)request.getParameter("form_id");
		//System.out.println("Delete form : "+form_id);
		IForm form = new Form();
		form.setId(form_id);
		FormDao.getSharedFormDao().removeForm(form);
		response.sendRedirect(request.getContextPath()+servletDir+"/formList");
	}
	/**
	 * view to list all forms
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void formList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!UserLoggedCanRead(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/index?credentialError=true");
		}
		request.setAttribute("formList",FormDao.getSharedFormDao().getAllForms());

	}

	/**
	 * views for a form detail
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void formDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!UserLoggedCanRead(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/index?credentialError=true");
		}
		//System.out.println(FormDao.getSharedFormDao().getFormWithId(request.getParameter("form_id")).toString());
		request.setAttribute("form",FormDao.getSharedFormDao().getFormWithId(request.getParameter("form_id")));
	}

	/**
	 * view to edit form
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	public void formEdit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		if(!UserLoggedCanModify(request)){
			response.sendRedirect(request.getContextPath()+servletDir+"/index?credentialError=true");
		}
	}
	/**
	 * return a list a all form in xml format providing following datas:
	 * the id of the form
	 * the name of the form
	 * the number of questions in the form
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void getFormListWebService(HttpServletRequest request, HttpServletResponse response) throws IOException{
		ArrayList<IForm> formList= (ArrayList<IForm>) FormDao.getSharedFormDao().getAllForms();
		Writer writer = response.getWriter();
		writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		writer.write("<forms>");
		for(IForm form : formList){
			writer.write("<form>");
				writer.write("<id>");
					writer.write(""+form.getId());
				writer.write("</id>");
				writer.write("<name>");
					writer.write(""+form.getName());
				writer.write("</name>");
				writer.write("<questionCount>");
					writer.write(""+form.getQuestions().size());
				writer.write("</questionCount>");
			writer.write("</form>");
		}
		writer.write("</forms>");
	}
	
	/**
	 * simply prints a form file(xml) 
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	public void getFormWebService(HttpServletRequest request, HttpServletResponse response) throws IOException{
		String formId = request.getParameter("form_id");
		File formFile = FormDao.getSharedFormDao().getFileFormWithId(formId);
		Writer writer = response.getWriter();
		FileReader fr = new FileReader(formFile);
		BufferedReader bfr = new BufferedReader(fr);
		String s = null;
		while(null != (s = bfr.readLine())){
			writer.write(s);	
		}
		bfr.close();
		//System.out.println(formFile.getAbsolutePath());
	}

}
